package com.xunji.user.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * 音频编解码工具：
 * <ul>
 * <li>1、8k16bitPCM、8kAlaw、 muLaw直接转换。</li>
 * <li>2、立体音 分离 成单声道（立体语音是Alaw）</li>
 * </ul>
 *
 * @author lyhu
 */
public class AudioUtil {
    static byte ALawCompressTable[] = {1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
            5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7,
            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
            7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};

    static short ALawDecompressTable[] = {(short) 0xEA80, (short) 0xEB80, (short) 0xE880, (short) 0xE980, (short) 0xEE80,
            (short) 0xEF80, (short) 0xEC80, (short) 0xED80, (short) 0xE280, (short) 0xE380, (short) 0xE080, (short) 0xE180,
            (short) 0xE680, (short) 0xE780, (short) 0xE480, (short) 0xE580, (short) 0xF540, (short) 0xF5C0, (short) 0xF440,
            (short) 0xF4C0, (short) 0xF740, (short) 0xF7C0, (short) 0xF640, (short) 0xF6C0, (short) 0xF140, (short) 0xF1C0,
            (short) 0xF040, (short) 0xF0C0, (short) 0xF340, (short) 0xF3C0, (short) 0xF240, (short) 0xF2C0, (short) 0xAA00,
            (short) 0xAE00, (short) 0xA200, (short) 0xA600, (short) 0xBA00, (short) 0xBE00, (short) 0xB200, (short) 0xB600,
            (short) 0x8A00, (short) 0x8E00, (short) 0x8200, (short) 0x8600, (short) 0x9A00, (short) 0x9E00, (short) 0x9200,
            (short) 0x9600, (short) 0xD500, (short) 0xD700, (short) 0xD100, (short) 0xD300, (short) 0xDD00, (short) 0xDF00,
            (short) 0xD900, (short) 0xDB00, (short) 0xC500, (short) 0xC700, (short) 0xC100, (short) 0xC300, (short) 0xCD00,
            (short) 0xCF00, (short) 0xC900, (short) 0xCB00, (short) 0xFEA8, (short) 0xFEB8, (short) 0xFE88, (short) 0xFE98,
            (short) 0xFEE8, (short) 0xFEF8, (short) 0xFEC8, (short) 0xFED8, (short) 0xFE28, (short) 0xFE38, (short) 0xFE08,
            (short) 0xFE18, (short) 0xFE68, (short) 0xFE78, (short) 0xFE48, (short) 0xFE58, (short) 0xFFA8, (short) 0xFFB8,
            (short) 0xFF88, (short) 0xFF98, (short) 0xFFE8, (short) 0xFFF8, (short) 0xFFC8, (short) 0xFFD8, (short) 0xFF28,
            (short) 0xFF38, (short) 0xFF08, (short) 0xFF18, (short) 0xFF68, (short) 0xFF78, (short) 0xFF48, (short) 0xFF58,
            (short) 0xFAA0, (short) 0xFAE0, (short) 0xFA20, (short) 0xFA60, (short) 0xFBA0, (short) 0xFBE0, (short) 0xFB20,
            (short) 0xFB60, (short) 0xF8A0, (short) 0xF8E0, (short) 0xF820, (short) 0xF860, (short) 0xF9A0, (short) 0xF9E0,
            (short) 0xF920, (short) 0xF960, (short) 0xFD50, (short) 0xFD70, (short) 0xFD10, (short) 0xFD30, (short) 0xFDD0,
            (short) 0xFDF0, (short) 0xFD90, (short) 0xFDB0, (short) 0xFC50, (short) 0xFC70, (short) 0xFC10, (short) 0xFC30,
            (short) 0xFCD0, (short) 0xFCF0, (short) 0xFC90, (short) 0xFCB0, (short) 0x1580, (short) 0x1480, (short) 0x1780,
            (short) 0x1680, (short) 0x1180, (short) 0x1080, (short) 0x1380, (short) 0x1280, (short) 0x1D80, (short) 0x1C80,
            (short) 0x1F80, (short) 0x1E80, (short) 0x1980, (short) 0x1880, (short) 0x1B80, (short) 0x1A80, (short) 0x0AC0,
            (short) 0x0A40, (short) 0x0BC0, (short) 0x0B40, (short) 0x08C0, (short) 0x0840, (short) 0x09C0, (short) 0x0940,
            (short) 0x0EC0, (short) 0x0E40, (short) 0x0FC0, (short) 0x0F40, (short) 0x0CC0, (short) 0x0C40, (short) 0x0DC0,
            (short) 0x0D40, (short) 0x5600, (short) 0x5200, (short) 0x5E00, (short) 0x5A00, (short) 0x4600, (short) 0x4200,
            (short) 0x4E00, (short) 0x4A00, (short) 0x7600, (short) 0x7200, (short) 0x7E00, (short) 0x7A00, (short) 0x6600,
            (short) 0x6200, (short) 0x6E00, (short) 0x6A00, (short) 0x2B00, (short) 0x2900, (short) 0x2F00, (short) 0x2D00,
            (short) 0x2300, (short) 0x2100, (short) 0x2700, (short) 0x2500, (short) 0x3B00, (short) 0x3900, (short) 0x3F00,
            (short) 0x3D00, (short) 0x3300, (short) 0x3100, (short) 0x3700, (short) 0x3500, (short) 0x0158, (short) 0x0148,
            (short) 0x0178, (short) 0x0168, (short) 0x0118, (short) 0x0108, (short) 0x0138, (short) 0x0128, (short) 0x01D8,
            (short) 0x01C8, (short) 0x01F8, (short) 0x01E8, (short) 0x0198, (short) 0x0188, (short) 0x01B8, (short) 0x01A8,
            (short) 0x0058, (short) 0x0048, (short) 0x0078, (short) 0x0068, (short) 0x0018, (short) 0x0008, (short) 0x0038,
            (short) 0x0028, (short) 0x00D8, (short) 0x00C8, (short) 0x00F8, (short) 0x00E8, (short) 0x0098, (short) 0x0088,
            (short) 0x00B8, (short) 0x00A8, (short) 0x0560, (short) 0x0520, (short) 0x05E0, (short) 0x05A0, (short) 0x0460,
            (short) 0x0420, (short) 0x04E0, (short) 0x04A0, (short) 0x0760, (short) 0x0720, (short) 0x07E0, (short) 0x07A0,
            (short) 0x0660, (short) 0x0620, (short) 0x06E0, (short) 0x06A0, (short) 0x02B0, (short) 0x0290, (short) 0x02F0,
            (short) 0x02D0, (short) 0x0230, (short) 0x0210, (short) 0x0270, (short) 0x0250, (short) 0x03B0, (short) 0x0390,
            (short) 0x03F0, (short) 0x03D0, (short) 0x0330, (short) 0x0310, (short) 0x0370, (short) 0x0350,};

    static byte MuLawCompressTable[] =
            {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
                    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
                    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
                    6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
                    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
                    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
                    7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7};

    static short MuLawDecompressTable[] = {(short) 0x8284, (short) 0x8684, (short) 0x8A84, (short) 0x8E84, (short) 0x9284,
            (short) 0x9684, (short) 0x9A84, (short) 0x9E84, (short) 0xA284, (short) 0xA684, (short) 0xAA84, (short) 0xAE84,
            (short) 0xB284, (short) 0xB684, (short) 0xBA84, (short) 0xBE84, (short) 0xC184, (short) 0xC384, (short) 0xC584,
            (short) 0xC784, (short) 0xC984, (short) 0xCB84, (short) 0xCD84, (short) 0xCF84, (short) 0xD184, (short) 0xD384,
            (short) 0xD584, (short) 0xD784, (short) 0xD984, (short) 0xDB84, (short) 0xDD84, (short) 0xDF84, (short) 0xE104,
            (short) 0xE204, (short) 0xE304, (short) 0xE404, (short) 0xE504, (short) 0xE604, (short) 0xE704, (short) 0xE804,
            (short) 0xE904, (short) 0xEA04, (short) 0xEB04, (short) 0xEC04, (short) 0xED04, (short) 0xEE04, (short) 0xEF04,
            (short) 0xF004, (short) 0xF0C4, (short) 0xF144, (short) 0xF1C4, (short) 0xF244, (short) 0xF2C4, (short) 0xF344,
            (short) 0xF3C4, (short) 0xF444, (short) 0xF4C4, (short) 0xF544, (short) 0xF5C4, (short) 0xF644, (short) 0xF6C4,
            (short) 0xF744, (short) 0xF7C4, (short) 0xF844, (short) 0xF8A4, (short) 0xF8E4, (short) 0xF924, (short) 0xF964,
            (short) 0xF9A4, (short) 0xF9E4, (short) 0xFA24, (short) 0xFA64, (short) 0xFAA4, (short) 0xFAE4, (short) 0xFB24,
            (short) 0xFB64, (short) 0xFBA4, (short) 0xFBE4, (short) 0xFC24, (short) 0xFC64, (short) 0xFC94, (short) 0xFCB4,
            (short) 0xFCD4, (short) 0xFCF4, (short) 0xFD14, (short) 0xFD34, (short) 0xFD54, (short) 0xFD74, (short) 0xFD94,
            (short) 0xFDB4, (short) 0xFDD4, (short) 0xFDF4, (short) 0xFE14, (short) 0xFE34, (short) 0xFE54, (short) 0xFE74,
            (short) 0xFE8C, (short) 0xFE9C, (short) 0xFEAC, (short) 0xFEBC, (short) 0xFECC, (short) 0xFEDC, (short) 0xFEEC,
            (short) 0xFEFC, (short) 0xFF0C, (short) 0xFF1C, (short) 0xFF2C, (short) 0xFF3C, (short) 0xFF4C, (short) 0xFF5C,
            (short) 0xFF6C, (short) 0xFF7C, (short) 0xFF88, (short) 0xFF90, (short) 0xFF98, (short) 0xFFA0, (short) 0xFFA8,
            (short) 0xFFB0, (short) 0xFFB8, (short) 0xFFC0, (short) 0xFFC8, (short) 0xFFD0, (short) 0xFFD8, (short) 0xFFE0,
            (short) 0xFFE8, (short) 0xFFF0, (short) 0xFFF8, (short) 0x0000, (short) 0x7D7C, (short) 0x797C, (short) 0x757C,
            (short) 0x717C, (short) 0x6D7C, (short) 0x697C, (short) 0x657C, (short) 0x617C, (short) 0x5D7C, (short) 0x597C,
            (short) 0x557C, (short) 0x517C, (short) 0x4D7C, (short) 0x497C, (short) 0x457C, (short) 0x417C, (short) 0x3E7C,
            (short) 0x3C7C, (short) 0x3A7C, (short) 0x387C, (short) 0x367C, (short) 0x347C, (short) 0x327C, (short) 0x307C,
            (short) 0x2E7C, (short) 0x2C7C, (short) 0x2A7C, (short) 0x287C, (short) 0x267C, (short) 0x247C, (short) 0x227C,
            (short) 0x207C, (short) 0x1EFC, (short) 0x1DFC, (short) 0x1CFC, (short) 0x1BFC, (short) 0x1AFC, (short) 0x19FC,
            (short) 0x18FC, (short) 0x17FC, (short) 0x16FC, (short) 0x15FC, (short) 0x14FC, (short) 0x13FC, (short) 0x12FC,
            (short) 0x11FC, (short) 0x10FC, (short) 0x0FFC, (short) 0x0F3C, (short) 0x0EBC, (short) 0x0E3C, (short) 0x0DBC,
            (short) 0x0D3C, (short) 0x0CBC, (short) 0x0C3C, (short) 0x0BBC, (short) 0x0B3C, (short) 0x0ABC, (short) 0x0A3C,
            (short) 0x09BC, (short) 0x093C, (short) 0x08BC, (short) 0x083C, (short) 0x07BC, (short) 0x075C, (short) 0x071C,
            (short) 0x06DC, (short) 0x069C, (short) 0x065C, (short) 0x061C, (short) 0x05DC, (short) 0x059C, (short) 0x055C,
            (short) 0x051C, (short) 0x04DC, (short) 0x049C, (short) 0x045C, (short) 0x041C, (short) 0x03DC, (short) 0x039C,
            (short) 0x036C, (short) 0x034C, (short) 0x032C, (short) 0x030C, (short) 0x02EC, (short) 0x02CC, (short) 0x02AC,
            (short) 0x028C, (short) 0x026C, (short) 0x024C, (short) 0x022C, (short) 0x020C, (short) 0x01EC, (short) 0x01CC,
            (short) 0x01AC, (short) 0x018C, (short) 0x0174, (short) 0x0164, (short) 0x0154, (short) 0x0144, (short) 0x0134,
            (short) 0x0124, (short) 0x0114, (short) 0x0104, (short) 0x00F4, (short) 0x00E4, (short) 0x00D4, (short) 0x00C4,
            (short) 0x00B4, (short) 0x00A4, (short) 0x0094, (short) 0x0084, (short) 0x0078, (short) 0x0070, (short) 0x0068,
            (short) 0x0060, (short) 0x0058, (short) 0x0050, (short) 0x0048, (short) 0x0040, (short) 0x0038, (short) 0x0030,
            (short) 0x0028, (short) 0x0020, (short) 0x0018, (short) 0x0010, (short) 0x0008, (short) 0x0000};

    /**
     * Alaw Linear Input Code Compressed Code ------------------------ --------------- 0000000wxyza
     * 000wxyz 0000001wxyza 001wxyz 000001wxyzab 010wxyz 00001wxyzabc 011wxyz 0001wxyzabcd 100wxyz
     * 001wxyzabcde 101wxyz 01wxyzabcdef 110wxyz 1wxyzabcdefg 111wxyz
     */

    public static byte linearToAlawSample(short sample) {
        int sign = 0;
        int exponent = 0;
        int mantissa = 0;
        int compressedByte = 0;

        sign = ((~sample) >> 8) & 0x80;
        if (sign == 0) {
            sample = (short) -sample;
        }
        if (sample > 0x7F7B) {
            sample = 0x7F7B;
        }
        if (sample >= 0x100) {
            exponent = ALawCompressTable[(sample >> 8) & 0x7F];
            mantissa = (sample >> (exponent + 3)) & 0x0F;
            compressedByte = ((exponent << 4) | mantissa);
        } else {
            compressedByte = (sample >> 4);
        }
        compressedByte ^= (sign ^ 0x55);
        return (byte) compressedByte;
    }

    /**
     * 8k16bit pcm 转化 8kAlaw
     *
     * @param in
     * @return
     * @throws IOException
     */
    public static ByteArrayOutputStream linearToAlawSample(InputStream in) throws IOException {

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

        byte[] targets = new byte[2];
        while (in.available() > 0) {
            in.read(targets);
            outputStream.write(linearToAlawSample((short) (((targets[1] & 0xFF) << 8) | (targets[0] & 0xFF))));
        }
        return outputStream;
    }


    /**
     * 合并双声道音频，16位分辨率
     * @param ch1
     * @param ch2
     * @param littleEndian
     * @return
     * @throws Exception
     */
    public static byte[] mergeChannel(byte[] ch1,byte[] ch2,boolean littleEndian) throws Exception {
        /*if(ch1 == null || ch2 == null || (ch1.length != ch2.length)){
            throw new Exception("音频声道源长度不同");
        }*/

        if(ch1 == null)return ch2;
        if(ch2 == null)return ch1;

        int length = ch1.length;
        byte[] mix = new byte[length];
        for(int i=0;i<length;){
            short sh1 = 0;
            short sh2 = 0;
            if(littleEndian){
                sh1 =  (short) (sh1 | (ch1[i] & 0xFF) | ((ch1[i+1] & 0xFF) <<8)) ;
                sh2 =  (short)( sh2 | (ch2[i] & 0xFF) | ((ch2[i+1] & 0xFF) <<8));
            }else {
                sh1 =  (short) (sh1 | (ch1[i+1] & 0xFF) | ((ch1[i] & 0xFF) <<8));
                sh2 =  (short) (sh2 | (ch2[i+1] & 0xFF) | ((ch2[i] & 0xFF) <<8));
            }

            short left = (short) (sh1/2);
            short right = (short) (sh2/2);
            short sumst = (short) (left  + right);
            if(littleEndian){
                mix[i] = (byte) (sumst  & 0xFF);
                mix[i+1] = (byte) ((sumst>>8)  & 0xFF);
            }else {
                mix[i] = (byte) ((sumst>>>8)  & 0xFF);
                mix[i+1] = (byte) (sumst  & 0xFF);
            }
            i = i+2;
        }
        return mix;
    }



    /**
     * 8kAlaw => 8k16bit pcm
     *
     * @param in
     * @return
     * @throws IOException
     */
    public static ByteArrayOutputStream alawToLinearSample(InputStream in) throws IOException {

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] targets = new byte[1];
        while (in.available() > 0) {
            in.read(targets);
            outputStream.write(alawToLinearSampleByte(targets[0]));
        }

        return outputStream;
    }

    public static short alawToLinearSample(byte sample) {
        return ALawDecompressTable[sample & 0xFF];
    }

    public static byte[] alawToLinearSampleByte(byte sample) {
        short s = alawToLinearSample(sample);
        byte[] targets = new byte[2];
        targets[1] = (byte) (s >> 8);
        targets[0] = (byte) (s >> 0);
        return targets;
    }

    /**
     * 讲Alaw数组转成标准byte[]
     */
    public static byte[] alaw2normal(byte[] bs) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        for (byte b : bs) {
            try {
                outputStream.write(AudioUtil.alawToLinearSampleByte(b));
            } catch (IOException e) {
            }
        }
        return outputStream.toByteArray();
    }

    /**
     * ulaw Biased Linear Input Code Compressed Code ------------------------ ---------------
     * 00000001wxyza 000wxyz 0000001wxyzab 001wxyz 000001wxyzabc 010wxyz 00001wxyzabcd 011wxyz
     * 0001wxyzabcde 100wxyz 001wxyzabcdef 101wxyz 01wxyzabcdefg 110wxyz 1wxyzabcdefgh 111wxyz
     */

    public static byte linearToMuLawSample(short sample) {
        int cBias = 0x84;
        int cClip = 0x7F7B;
        int sign = (sample >> 8) & 0x80;
        if (sign != 0) {
            sample = (short) -sample;
        }
        if (sample > cClip) {
            sample = (short) cClip;
        }
        sample = (short) (sample + cBias);

        int exponent = MuLawCompressTable[(sample >> 7) & 0xFF];
        int mantissa = (sample >> (exponent + 3)) & 0x0F;
        int compressedByte = ~(sign | (exponent << 4) | mantissa);
        return (byte) compressedByte;
    }

    public static short muLawToLinearSample(byte sample) {
        return MuLawDecompressTable[sample];
    }

    public static byte[] muLawToLinearSampleByte(byte sample) {
        short s = MuLawDecompressTable[sample];
        byte[] targets = new byte[2];
        targets[1] = (byte) (s >> 8);
        targets[0] = (byte) (s >> 0);
        return targets;
    }

    /**
     * 立体音 分离 成单声道（立体语音是8kAlaw）
     *
     * @param stereoBytes
     * @return
     * @throws IOException
     */
    public static byte[][] stereo2MonoForAlaw(byte[] stereoBytes) throws IOException {

        byte[][] objList = new byte[2][];

        try (ByteArrayOutputStream outputStreamL = new ByteArrayOutputStream()) {
            try (ByteArrayOutputStream outputStreamR = new ByteArrayOutputStream()) {

                for (int i = 0; i < stereoBytes.length; i = i + 2) {
                    outputStreamL.write(stereoBytes[i]);
                    outputStreamR.write(stereoBytes[i + 1]);
                }
                outputStreamL.flush();
                outputStreamR.flush();
                objList[0] = outputStreamL.toByteArray();
                objList[1] = outputStreamR.toByteArray();
            }
        }
        return objList;
    }

    /**
     * 立体音 分离 成单声道（立体语音是16k16bit）
     *
     * @param stereoBytes
     * @return
     * @throws IOException
     */
    public static byte[][] stereo2MonoFor16Bit(byte[] stereoBytes) throws IOException {

        byte[][] objList = new byte[2][];

        try (ByteArrayOutputStream outputStreamL = new ByteArrayOutputStream()) {
            try (ByteArrayOutputStream outputStreamR = new ByteArrayOutputStream()) {

                for (int i = 0; i < stereoBytes.length; i = i + 4) {
                    outputStreamL.write(stereoBytes[i]);
                    outputStreamL.write(stereoBytes[i + 1]);
                    outputStreamR.write(stereoBytes[i + 2]);
                    outputStreamR.write(stereoBytes[i + 3]);
                }
                outputStreamL.flush();
                outputStreamR.flush();
                objList[0] = outputStreamL.toByteArray();
                objList[1] = outputStreamR.toByteArray();
            }
        }
        return objList;
    }

    /**
     * 单声道(8K16bit) 合成 立体音
     *
     * @param left
     * @param right
     * @return byte数组
     */
    public static byte[] line2stereo(byte[] left, byte[] right) {
        int length = Math.min(left.length, right.length) * 2;
        byte[] stereoBytes = new byte[length];
        for (int i = 0, j = 0, k = 0; i < length; ) {
            stereoBytes[i++] = left[j++];
            stereoBytes[i++] = left[j++];
            stereoBytes[i++] = right[k++];
            stereoBytes[i++] = right[k++];
        }
        return stereoBytes;
    }


    /**
     * 计算立体声音频数据中某个通道的能量值
     *
     * @param buffer        一段立体声的音频采样数据
     * @param channelCount  代表立体声中含有多少个通道
     * @param channelNumber 代表立体声中的哪个通道
     * @return 返回能量值，取值范围是0.0~1.0
     */

    public static double calculateVolume(byte[] buffer, int channelCount, int channelNumber) {
        double sumVolume = 0.0;
        double avgVolume = 0.0;
        double volume = 0.0;

        for (int i = channelNumber; i < buffer.length; i += channelCount) {
            sumVolume += Math.abs(buffer[i]);
        }
        avgVolume = sumVolume / (buffer.length / channelCount);
        volume = Math.log10(1 + avgVolume) * 10;
        volume = volume / 45.1545;

        return Double.valueOf(String.format("%.3f", volume));
    }

    /**
     * 计算单声道音频能量值
     *
     * @param buffer 一段立体声的音频采样数据
     * @return 返回能量值，取值范围是0.0~1.0
     */
    public static double calVolForline(byte[] buffer) {
        double sumVolume = 0.0;
        double avgVolume = 0.0;
        double volume = 0.0;

        for (int i = 0; i < buffer.length; i++) {
            sumVolume += Math.abs(buffer[i]);
        }

        avgVolume = sumVolume / buffer.length;
        volume = 20 * Math.log10(1 + avgVolume);
        volume = volume / 100.00;
        return Double.valueOf(String.format("%.3f", volume));
    }

    /**
     * 拼接byte[]
     *
     * @param orig 原始byte[]
     * @param dest 需要拼接的数据
     * @return byte[]
     */
    public static byte[] append(byte[] orig, byte[] dest) {

        byte[] newByte = new byte[orig.length + dest.length];

        System.arraycopy(orig, 0, newByte, 0, orig.length);
        System.arraycopy(dest, 0, newByte, orig.length, dest.length);

        return newByte;

    }


    public static short[] bytesToShort(byte[] bytes) {
        if (bytes == null) {
            return null;
        }
        short[] shorts = new short[bytes.length / 2];
        ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
        return shorts;
    }

    public static double calPower(byte[] bytes){
        short[] shorts = bytesToShort(bytes);
        long sum = 0;
        for(short ee:shorts){
            sum+= (ee*ee);
        }
        double averagePower = sum/(double)shorts.length;
        double log = 10 * Math.log10(averagePower);
        return log;
    }



}
